summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-04 16:06:09 +1000
committerQt by Nokia <qt-info@nokia.com>2012-06-13 09:56:37 +0200
commitccad1b6e4ca295861ff50b8e84560dd9769930d1 (patch)
treefd180f05ac14f4f806711ce4f2316d899a1536d5
parentc010afb5a3c2948730ab9b35baa3deba1acb6531 (diff)
[V8] Generalize external object resources
V8 was already able to manage and finalize an external string resource. This change generalizes that mechanism to handle a single generic external resource - a v8::Object::ExternalResource derived instance - on normal JSObject's. This is useful for mapping C++ objects to JS objects where the C++ object's memory is effectively owned by the JS Object, and thus needs to destroyed when the JS Object is garbage collected. The V8 mailing list suggests using a weak persistent handle for this purpose, but that seems to incur a fairly massive performance penalty for short lived objects as weak persistent handle callbacks are not called until the object has been promoted into the old object space. Change-Id: I8f1a1f2a2be052339e8507b98058b289c7f16b0a Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
-rw-r--r--src/3rdparty/v8/include/v8.h25
-rw-r--r--src/3rdparty/v8/src/api.cc56
-rw-r--r--src/3rdparty/v8/src/factory.cc11
-rw-r--r--src/3rdparty/v8/src/heap-inl.h59
-rw-r--r--src/3rdparty/v8/src/heap.cc29
-rw-r--r--src/3rdparty/v8/src/heap.h16
-rw-r--r--src/3rdparty/v8/src/mark-compact.cc13
-rw-r--r--src/3rdparty/v8/src/objects-inl.h35
-rw-r--r--src/3rdparty/v8/src/objects.h19
9 files changed, 221 insertions, 42 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h
index 8c9ee35..5cc8e6f 100644
--- a/src/3rdparty/v8/include/v8.h
+++ b/src/3rdparty/v8/include/v8.h
@@ -1614,6 +1614,25 @@ class Object : public Value {
/** Sets a native pointer in an internal field. */
V8EXPORT void SetPointerInInternalField(int index, void* value);
+ class V8EXPORT ExternalResource { // NOLINT
+ public:
+ ExternalResource() {}
+ virtual ~ExternalResource() {}
+
+ protected:
+ virtual void Dispose() { delete this; }
+
+ private:
+ // Disallow copying and assigning.
+ ExternalResource(const ExternalResource&);
+ void operator=(const ExternalResource&);
+
+ friend class v8::internal::Heap;
+ };
+
+ V8EXPORT void SetExternalResource(ExternalResource *);
+ V8EXPORT ExternalResource *GetExternalResource();
+
// Testers for local properties.
V8EXPORT bool HasOwnProperty(Handle<String> key);
V8EXPORT bool HasRealNamedProperty(Handle<String> key);
@@ -2503,6 +2522,12 @@ class V8EXPORT ObjectTemplate : public Template {
*/
void SetInternalFieldCount(int value);
+ /**
+ * Sets whether the object can store an "external resource" object.
+ */
+ bool HasExternalResource();
+ void SetHasExternalResource(bool value);
+
private:
ObjectTemplate();
static Local<ObjectTemplate> New(Handle<FunctionTemplate> constructor);
diff --git a/src/3rdparty/v8/src/api.cc b/src/3rdparty/v8/src/api.cc
index d31269c..2de7bb8 100644
--- a/src/3rdparty/v8/src/api.cc
+++ b/src/3rdparty/v8/src/api.cc
@@ -1465,6 +1465,34 @@ void ObjectTemplate::SetInternalFieldCount(int value) {
}
+bool ObjectTemplate::HasExternalResource()
+{
+ if (IsDeadCheck(Utils::OpenHandle(this)->GetIsolate(),
+ "v8::ObjectTemplate::HasExternalResource()")) {
+ return 0;
+ }
+ return !Utils::OpenHandle(this)->has_external_resource()->IsUndefined();
+}
+
+
+void ObjectTemplate::SetHasExternalResource(bool value)
+{
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetHasExternalResource()")) {
+ return;
+ }
+ ENTER_V8(isolate);
+ if (value) {
+ EnsureConstructor(this);
+ }
+ if (value) {
+ Utils::OpenHandle(this)->set_has_external_resource(i::Smi::FromInt(1));
+ } else {
+ Utils::OpenHandle(this)->set_has_external_resource(Utils::OpenHandle(this)->GetHeap()->undefined_value());
+ }
+}
+
+
// --- S c r i p t D a t a ---
@@ -4266,6 +4294,34 @@ void v8::Object::SetPointerInInternalField(int index, void* value) {
}
+void v8::Object::SetExternalResource(v8::Object::ExternalResource *resource) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ENTER_V8(isolate);
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ if (CanBeEncodedAsSmi(resource)) {
+ obj->SetExternalResourceObject(EncodeAsSmi(resource));
+ } else {
+ obj->SetExternalResourceObject(*isolate->factory()->NewForeign(static_cast<i::Address>((void *)resource)));
+ }
+ if (!obj->IsSymbol()) {
+ isolate->heap()->external_string_table()->AddObject(*obj);
+ }
+}
+
+
+v8::Object::ExternalResource *v8::Object::GetExternalResource() {
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Object* value = obj->GetExternalResourceObject();
+ if (value->IsSmi()) {
+ return reinterpret_cast<v8::Object::ExternalResource*>(i::Internals::GetExternalPointerFromSmi(value));
+ } else if (value->IsForeign()) {
+ return reinterpret_cast<v8::Object::ExternalResource*>(i::Foreign::cast(value)->foreign_address());
+ } else {
+ return NULL;
+ }
+}
+
+
// --- E n v i r o n m e n t ---
diff --git a/src/3rdparty/v8/src/factory.cc b/src/3rdparty/v8/src/factory.cc
index 2d1535f..1e8938a 100644
--- a/src/3rdparty/v8/src/factory.cc
+++ b/src/3rdparty/v8/src/factory.cc
@@ -1234,15 +1234,21 @@ Handle<JSFunction> Factory::CreateApiFunction(
Handle<Code> construct_stub = isolate()->builtins()->JSConstructStubApi();
int internal_field_count = 0;
+ bool has_external_resource = false;
+
if (!obj->instance_template()->IsUndefined()) {
Handle<ObjectTemplateInfo> instance_template =
Handle<ObjectTemplateInfo>(
ObjectTemplateInfo::cast(obj->instance_template()));
internal_field_count =
Smi::cast(instance_template->internal_field_count())->value();
+ has_external_resource =
+ !instance_template->has_external_resource()->IsUndefined();
}
int instance_size = kPointerSize * internal_field_count;
+ if (has_external_resource) instance_size += kPointerSize;
+
InstanceType type = INVALID_TYPE;
switch (instance_type) {
case JavaScriptObject:
@@ -1277,6 +1283,11 @@ Handle<JSFunction> Factory::CreateApiFunction(
Handle<Map> map = Handle<Map>(result->initial_map());
+ // Mark as having external data object if needed
+ if (has_external_resource) {
+ map->set_has_external_resource(true);
+ }
+
// Mark as undetectable if needed.
if (obj->undetectable()) {
map->set_is_undetectable();
diff --git a/src/3rdparty/v8/src/heap-inl.h b/src/3rdparty/v8/src/heap-inl.h
index ea14dbf..3e036b6 100644
--- a/src/3rdparty/v8/src/heap-inl.h
+++ b/src/3rdparty/v8/src/heap-inl.h
@@ -246,18 +246,33 @@ MaybeObject* Heap::NumberFromUint32(
}
-void Heap::FinalizeExternalString(String* string) {
- ASSERT(string->IsExternalString());
- v8::String::ExternalStringResourceBase** resource_addr =
- reinterpret_cast<v8::String::ExternalStringResourceBase**>(
- reinterpret_cast<byte*>(string) +
- ExternalString::kResourceOffset -
- kHeapObjectTag);
-
- // Dispose of the C++ object if it has not already been disposed.
- if (*resource_addr != NULL) {
- (*resource_addr)->Dispose();
- *resource_addr = NULL;
+void Heap::FinalizeExternalString(HeapObject* string) {
+ ASSERT(string->IsExternalString() || string->map()->has_external_resource());
+
+ if (string->IsExternalString()) {
+ v8::String::ExternalStringResourceBase** resource_addr =
+ reinterpret_cast<v8::String::ExternalStringResourceBase**>(
+ reinterpret_cast<byte*>(string) +
+ ExternalString::kResourceOffset -
+ kHeapObjectTag);
+
+ // Dispose of the C++ object if it has not already been disposed.
+ if (*resource_addr != NULL) {
+ (*resource_addr)->Dispose();
+ *resource_addr = NULL;
+ }
+ } else {
+ JSObject *object = JSObject::cast(string);
+ Object *value = object->GetExternalResourceObject();
+ v8::Object::ExternalResource *resource = 0;
+ if (value->IsSmi()) {
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(Internals::GetExternalPointerFromSmi(value));
+ } else if (value->IsForeign()) {
+ resource = reinterpret_cast<v8::Object::ExternalResource*>(Foreign::cast(value)->foreign_address());
+ }
+ if (resource) {
+ resource->Dispose();
+ }
}
}
@@ -580,6 +595,16 @@ void ExternalStringTable::AddString(String* string) {
}
+void ExternalStringTable::AddObject(HeapObject* object) {
+ ASSERT(object->map()->has_external_resource());
+ if (heap_->InNewSpace(object)) {
+ new_space_strings_.Add(object);
+ } else {
+ old_space_strings_.Add(object);
+ }
+}
+
+
void ExternalStringTable::Iterate(ObjectVisitor* v) {
if (!new_space_strings_.is_empty()) {
Object** start = &new_space_strings_[0];
@@ -608,14 +633,14 @@ void ExternalStringTable::Verify() {
}
-void ExternalStringTable::AddOldString(String* string) {
- ASSERT(string->IsExternalString());
- ASSERT(!heap_->InNewSpace(string));
- old_space_strings_.Add(string);
+void ExternalStringTable::AddOldObject(HeapObject* object) {
+ ASSERT(object->IsExternalString() || object->map()->has_external_resource());
+ ASSERT(!heap_->InNewSpace(object));
+ old_space_strings_.Add(object);
}
-void ExternalStringTable::ShrinkNewStrings(int position) {
+void ExternalStringTable::ShrinkNewObjects(int position) {
new_space_strings_.Rewind(position);
if (FLAG_verify_heap) {
Verify();
diff --git a/src/3rdparty/v8/src/heap.cc b/src/3rdparty/v8/src/heap.cc
index 937552a..73f291c 100644
--- a/src/3rdparty/v8/src/heap.cc
+++ b/src/3rdparty/v8/src/heap.cc
@@ -1274,18 +1274,18 @@ void Heap::Scavenge() {
}
-String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+HeapObject* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord first_word = HeapObject::cast(*p)->map_word();
if (!first_word.IsForwardingAddress()) {
// Unreachable external string can be finalized.
- heap->FinalizeExternalString(String::cast(*p));
+ heap->FinalizeExternalString(HeapObject::cast(*p));
return NULL;
}
// String is still reachable.
- return String::cast(first_word.ToForwardingAddress());
+ return HeapObject::cast(first_word.ToForwardingAddress());
}
@@ -1303,11 +1303,11 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
for (Object** p = start; p < end; ++p) {
ASSERT(InFromSpace(*p));
- String* target = updater_func(this, p);
+ HeapObject* target = updater_func(this, p);
if (target == NULL) continue;
- ASSERT(target->IsExternalString());
+ ASSERT(target->IsExternalString() || target->map()->has_external_resource());
if (InNewSpace(target)) {
// String is still in new space. Update the table entry.
@@ -1315,12 +1315,12 @@ void Heap::UpdateNewSpaceReferencesInExternalStringTable(
++last;
} else {
// String got promoted. Move it to the old string list.
- external_string_table_.AddOldString(target);
+ external_string_table_.AddOldObject(target);
}
}
ASSERT(last <= end);
- external_string_table_.ShrinkNewStrings(static_cast<int>(last - start));
+ external_string_table_.ShrinkNewObjects(static_cast<int>(last - start));
}
@@ -7068,6 +7068,19 @@ void ExternalStringTable::CleanUp() {
void ExternalStringTable::TearDown() {
+ for (int i = 0; i < new_space_strings_.length(); ++i) {
+ if (new_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(new_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+ for (int i = 0; i < old_space_strings_.length(); ++i) {
+ if (old_space_strings_[i] == heap_->raw_unchecked_null_value()) continue;
+ HeapObject *object = HeapObject::cast(old_space_strings_[i]);
+ if (!object->IsExternalString())
+ heap_->FinalizeExternalString(object);
+ }
+
new_space_strings_.Free();
old_space_strings_.Free();
}
diff --git a/src/3rdparty/v8/src/heap.h b/src/3rdparty/v8/src/heap.h
index beb1bc5..ba53909 100644
--- a/src/3rdparty/v8/src/heap.h
+++ b/src/3rdparty/v8/src/heap.h
@@ -253,8 +253,8 @@ class Isolate;
class WeakObjectRetainer;
-typedef String* (*ExternalStringTableUpdaterCallback)(Heap* heap,
- Object** pointer);
+typedef HeapObject* (*ExternalStringTableUpdaterCallback)(Heap* heap,
+ Object** pointer);
class StoreBufferRebuilder {
public:
@@ -390,10 +390,14 @@ typedef void (*ScavengingCallback)(Map* map,
// External strings table is a place where all external strings are
// registered. We need to keep track of such strings to properly
// finalize them.
+// The ExternalStringTable can contain both strings and objects with
+// external resources. It was not renamed to make the patch simpler.
class ExternalStringTable {
public:
// Registers an external string.
inline void AddString(String* string);
+ // Registers an external object.
+ inline void AddObject(HeapObject* string);
inline void Iterate(ObjectVisitor* v);
@@ -411,10 +415,10 @@ class ExternalStringTable {
inline void Verify();
- inline void AddOldString(String* string);
+ inline void AddOldObject(HeapObject* string);
// Notifies the table that only a prefix of the new list is valid.
- inline void ShrinkNewStrings(int position);
+ inline void ShrinkNewObjects(int position);
// To speed up scavenge collections new space string are kept
// separate from old space strings.
@@ -960,7 +964,7 @@ class Heap {
// Finalizes an external string by deleting the associated external
// data and clearing the resource pointer.
- inline void FinalizeExternalString(String* string);
+ inline void FinalizeExternalString(HeapObject* string);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
@@ -1847,7 +1851,7 @@ class Heap {
// Performs a minor collection in new generation.
void Scavenge();
- static String* UpdateNewSpaceReferenceInExternalStringTableEntry(
+ static HeapObject* UpdateNewSpaceReferenceInExternalStringTableEntry(
Heap* heap,
Object** pointer);
diff --git a/src/3rdparty/v8/src/mark-compact.cc b/src/3rdparty/v8/src/mark-compact.cc
index c455564..82fc1fc 100644
--- a/src/3rdparty/v8/src/mark-compact.cc
+++ b/src/3rdparty/v8/src/mark-compact.cc
@@ -1751,8 +1751,9 @@ class SymbolTableCleaner : public ObjectVisitor {
// Since no objects have yet been moved we can safely access the map of
// the object.
- if (o->IsExternalString()) {
- heap_->FinalizeExternalString(String::cast(*p));
+ if (o->IsExternalString() ||
+ (o->IsHeapObject() && HeapObject::cast(o)->map()->has_external_resource())) {
+ heap_->FinalizeExternalString(HeapObject::cast(*p));
}
// Set the entry to the_hole_value (as deleted).
*p = heap_->the_hole_value();
@@ -2743,15 +2744,15 @@ static void UpdatePointer(HeapObject** p, HeapObject* object) {
}
-static String* UpdateReferenceInExternalStringTableEntry(Heap* heap,
- Object** p) {
+static HeapObject* UpdateReferenceInExternalStringTableEntry(Heap* heap,
+ Object** p) {
MapWord map_word = HeapObject::cast(*p)->map_word();
if (map_word.IsForwardingAddress()) {
- return String::cast(map_word.ToForwardingAddress());
+ return HeapObject::cast(map_word.ToForwardingAddress());
}
- return String::cast(*p);
+ return HeapObject::cast(*p);
}
diff --git a/src/3rdparty/v8/src/objects-inl.h b/src/3rdparty/v8/src/objects-inl.h
index b026288..3c54afc 100644
--- a/src/3rdparty/v8/src/objects-inl.h
+++ b/src/3rdparty/v8/src/objects-inl.h
@@ -1483,7 +1483,7 @@ int JSObject::GetInternalFieldCount() {
// Make sure to adjust for the number of in-object properties. These
// properties do contribute to the size, but are not internal fields.
return ((Size() - GetHeaderSize()) >> kPointerSizeLog2) -
- map()->inobject_properties();
+ map()->inobject_properties() - (map()->has_external_resource()?1:0);
}
@@ -1523,6 +1523,23 @@ void JSObject::SetInternalField(int index, Smi* value) {
}
+void JSObject::SetExternalResourceObject(Object *value) {
+ ASSERT(map()->has_external_resource());
+ int offset = GetHeaderSize() + kPointerSize * GetInternalFieldCount();
+ WRITE_FIELD(this, offset, value);
+ WRITE_BARRIER(GetHeap(), this, offset, value);
+}
+
+
+Object *JSObject::GetExternalResourceObject() {
+ if (map()->has_external_resource()) {
+ return READ_FIELD(this, GetHeaderSize() + kPointerSize * GetInternalFieldCount());
+ } else {
+ return GetHeap()->undefined_value();
+ }
+}
+
+
// Access fast-case object properties at index. The use of these routines
// is needed to correctly distinguish between properties stored in-object and
// properties stored in the properties array.
@@ -2922,6 +2939,20 @@ bool Map::is_shared() {
return ((1 << kIsShared) & bit_field3()) != 0;
}
+void Map::set_has_external_resource(bool value) {
+ if (value) {
+ set_bit_field(bit_field() | (1 << kHasExternalResource));
+ } else {
+ set_bit_field(bit_field() & ~(1 << kHasExternalResource));
+ }
+}
+
+bool Map::has_external_resource()
+{
+ return ((1 << kHasExternalResource) & bit_field()) != 0;
+}
+
+
void Map::set_named_interceptor_is_fallback(bool value) {
if (value) {
set_bit_field3(bit_field3() | (1 << kNamedInterceptorIsFallback));
@@ -3559,6 +3590,8 @@ ACCESSORS_TO_SMI(FunctionTemplateInfo, flag, kFlagOffset)
ACCESSORS(ObjectTemplateInfo, constructor, Object, kConstructorOffset)
ACCESSORS(ObjectTemplateInfo, internal_field_count, Object,
kInternalFieldCountOffset)
+ACCESSORS(ObjectTemplateInfo, has_external_resource, Object,
+ kHasExternalResourceOffset)
ACCESSORS(SignatureInfo, receiver, Object, kReceiverOffset)
ACCESSORS(SignatureInfo, args, Object, kArgsOffset)
diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h
index d938c3f..a2884ca 100644
--- a/src/3rdparty/v8/src/objects.h
+++ b/src/3rdparty/v8/src/objects.h
@@ -1863,6 +1863,9 @@ class JSObject: public JSReceiver {
inline void SetInternalField(int index, Object* value);
inline void SetInternalField(int index, Smi* value);
+ inline void SetExternalResourceObject(Object *);
+ inline Object *GetExternalResourceObject();
+
// The following lookup functions skip interceptors.
void LocalLookupRealNamedProperty(String* name, LookupResult* result);
void LookupRealNamedProperty(String* name, LookupResult* result);
@@ -4620,11 +4623,11 @@ class Map: public HeapObject {
// Tells whether the instance has a call-as-function handler.
inline void set_has_instance_call_handler() {
- set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
+ set_bit_field3(bit_field3() | (1 << kHasInstanceCallHandler));
}
inline bool has_instance_call_handler() {
- return ((1 << kHasInstanceCallHandler) & bit_field()) != 0;
+ return ((1 << kHasInstanceCallHandler) & bit_field3()) != 0;
}
inline void set_is_extensible(bool value);
@@ -4701,6 +4704,11 @@ class Map: public HeapObject {
inline void set_named_interceptor_is_fallback(bool value);
inline bool named_interceptor_is_fallback();
+ // Tells whether the instance has the space for an external resource
+ // object
+ inline void set_has_external_resource(bool value);
+ inline bool has_external_resource();
+
// [prototype]: implicit prototype object.
DECL_ACCESSORS(prototype, Object)
@@ -4949,7 +4957,7 @@ class Map: public HeapObject {
static const int kHasNamedInterceptor = 3;
static const int kHasIndexedInterceptor = 4;
static const int kIsUndetectable = 5;
- static const int kHasInstanceCallHandler = 6;
+ static const int kHasExternalResource = 6;
static const int kIsAccessCheckNeeded = 7;
// Bit positions for bit field 2
@@ -4974,6 +4982,7 @@ class Map: public HeapObject {
// Bit positions for bit field 3
static const int kIsShared = 0;
static const int kNamedInterceptorIsFallback = 1;
+ static const int kHasInstanceCallHandler = 2;
// Layout of the default cache. It holds alternating name and code objects.
static const int kCodeCacheEntrySize = 2;
@@ -8356,6 +8365,7 @@ class ObjectTemplateInfo: public TemplateInfo {
public:
DECL_ACCESSORS(constructor, Object)
DECL_ACCESSORS(internal_field_count, Object)
+ DECL_ACCESSORS(has_external_resource, Object)
static inline ObjectTemplateInfo* cast(Object* obj);
@@ -8372,7 +8382,8 @@ class ObjectTemplateInfo: public TemplateInfo {
static const int kConstructorOffset = TemplateInfo::kHeaderSize;
static const int kInternalFieldCountOffset =
kConstructorOffset + kPointerSize;
- static const int kSize = kInternalFieldCountOffset + kPointerSize;
+ static const int kHasExternalResourceOffset = kInternalFieldCountOffset + kPointerSize;
+ static const int kSize = kHasExternalResourceOffset + kPointerSize;
};